#include "stdafx.h"
#include "Stream.h"
#include "Constants.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

bool CStream::CreateFolder(const wchar_t* szPath)
{
	CString strPath(szPath);
	strPath.TrimRight(_T('\\'));
	strPath += _T('\\');

	//check if folder exists
	if(_taccess(strPath.GetBuffer(), 0))
	{
		CString strBuffPath;
		int iSep = strPath.Find(_T('\\'));
		while(iSep != -1)
		{
			strBuffPath = strPath.Mid(0, iSep);
			if(!_taccess(strBuffPath.GetBuffer(), 0))
			{
				iSep = strPath.Find(_T('\\'), iSep+1);
				continue;
			}
			_tmkdir(strBuffPath.GetBuffer());
			iSep = strPath.Find(_T('\\'), iSep+1);
		}
	}
	return true;
}


bool CStream::DeleteFolder(const wchar_t* szPath)
{
	SHFILEOPSTRUCT   Op;
	ZeroMemory(&Op,   sizeof(Op));

	TCHAR   ToBuf[MAX_PATH];
	TCHAR   FromBuf[MAX_PATH];
	ZeroMemory(ToBuf,   sizeof(ToBuf));
	ZeroMemory(FromBuf,   sizeof(FromBuf));
	lstrcpy(FromBuf,   szPath);

	Op.hwnd   =   NULL;
	Op.pFrom   =   FromBuf;
	Op.pTo   =   ToBuf;
	Op.fFlags   =   FOF_SILENT|FOF_NOCONFIRMATION|FOF_NOERRORUI;
	Op.fAnyOperationsAborted   =   FALSE;
	Op.hNameMappings   =   NULL;
	Op.lpszProgressTitle   =   NULL;
	Op.wFunc   =   FO_DELETE;

	return SHFileOperation(&Op) == 0;
}

bool CStream::CopyFolder(const wchar_t* szFrom, const wchar_t* szTo, bool bCoverIfExists/* = true*/)
{
	bool bIsExist = (_taccess(szTo, 0) == 0);

	// folder already exist and not allow cover
	if(bIsExist && !bCoverIfExists) 
		return false;

	TCHAR buf[MAX_PATH];
	CString strFrom(szFrom);
	strFrom.TrimRight(_T('\\'));

	for (int i=0; i < strFrom.GetLength(); i++)
	{
		buf[i]=strFrom[i];
	}
	buf[strFrom.GetLength()] = 0;
	buf[strFrom.GetLength()+1] = 0;

	SHFILEOPSTRUCT Op;
	Op.wFunc = FO_COPY;
	Op.pFrom = buf;
	Op.pTo = szTo;
	Op.fFlags = FOF_SILENT|FOF_NOCONFIRMATION|FOF_NOCONFIRMMKDIR|FOF_NOERRORUI;
	return SHFileOperation(&Op) == 0;	
}

bool CStream::MoveFolder(const wchar_t* szFrom, const wchar_t* szTo, bool bCoverIfExists/* = true*/)
{
	bool bIsExist = (_taccess(szTo, 0) == 0);

	// folder already exist and not allow cover
	if(bIsExist && !bCoverIfExists) 
		return false;

	TCHAR buf[MAX_PATH];
	CString strFrom(szFrom);
	strFrom.TrimRight(_T('\\'));
	for (int i = 0; i < strFrom.GetLength(); i++)
	{
		buf[i]=strFrom[i];
	}
	buf[strFrom.GetLength()] = 0;
	buf[strFrom.GetLength()+1] = 0;

	SHFILEOPSTRUCT Op;
	Op.wFunc = FO_MOVE;
	Op.pFrom = buf;
	Op.pTo = szTo;
	Op.fFlags = FOF_SILENT|FOF_NOCONFIRMATION|FOF_NOCONFIRMMKDIR|FOF_NOERRORUI;

	return SHFileOperation(&Op) == 0;	
} 

bool CStream::RenameFolder(const wchar_t* szOrigion, const wchar_t* szNew, bool bCoverIfExists/* = true*/)
{
	CString strOrigin(szOrigion);
	strOrigin.TrimRight(_T('\\'));
	int nPos = strOrigin.ReverseFind(_T('\\'));
	CString strParent = strOrigin.Mid(0, nPos + 1);
	CString strFullNewPth = strParent + szNew;

	return MoveFolder(szOrigion, strFullNewPth.GetBuffer(), bCoverIfExists);
}

void CStream::FormatXML(const wchar_t* pszPath)
{
	wifstream in(pszPath);

	CString strcontent;

	size_t ticker = 0;

	CString strTab = _T("\t");
	CString strRtn = _T("\n");

	static wchar_t buffer[1024*1024];
	while(in.getline(buffer, 1024*1024))
	{
		CString str(buffer);

		int i = -1;
		int j = -1;

		while ( str.Find(_T("<")) != -1 && str.Find(_T(">")) != -1 )
		{       
			i = str.Find(_T("<"));
			j = str.Find(_T(">"));


			CString strTag = str.Mid(i, j + 1);

			if (str[i + 1] != _T('/') && str[j - 1] != _T('/')) // start of tag: <Root>
			{
				for (size_t k = 0; k < ticker; k ++)
				{
					strTag = strTab + strTag;
				}
				strTag += strRtn;

				ticker ++;
			}
			else
			{
				if (str[i + 1] == _T('/'))  // end of a tag: </bin>
				{
					ticker --;
					for (size_t k = 0; k < ticker; k ++)
					{
						strTag = strTab + strTag;
					}
					strTag += strRtn;
				}
				else                    // end of an empty tag:<folder1/>
				{
					for (size_t k = 0; k < ticker; k ++)
					{
						strTag = strTab + strTag;
					}
					strTag += strRtn;
				}
			}

			strcontent += strTag;

			str = str.Mid(j + 1, str.GetLength() - j - 1);
		}
	}
	in.close();

	ofstream of(pszPath);
	of << strcontent;
	of.close();
}

void CStream::InsertXML(const wchar_t* pszPath, 
						  const wchar_t* pszNodeName, 
						  const wchar_t* pszName, 
						  const wchar_t* pszValue, 
						  bool bNeedFormatFirst/* = false*/)
{
	if (bNeedFormatFirst)
		FormatXML(pszPath);

	std::vector<CString> veclines;

	wifstream in(pszPath);
	wchar_t buffer[1024];
	while(in.getline(buffer, 1024))
	{
		CString strline(buffer);

		// generate the match keyword
		CString strNodeName(pszNodeName);
		strNodeName.Insert(0, _T("<"));
		if(strline.Find(strNodeName) == -1)	
		{
			veclines.push_back(strline);
			continue;
		}

		// create the new name/value pair
		CString strName(pszName);
		CString strValue(pszValue);
		CString strPair = strName + _T("=\"") + strValue + _T("\"");
		if(strline.Find(_T("/>")) != -1)
			strline = strline.Mid(0, strline.GetLength() - 2) + _T(" ") + strPair + _T("/>");
		else if(strline.ReverseFind(_T('>')) != -1)
			strline = strline.Mid(0, strline.GetLength() - 1) + _T(" ") + strPair + _T(">");
		else // do nothing
		{}

		veclines.push_back(strline);
	}
	in.close();

	ofstream of(pszPath);
	for (size_t i = 0; i < veclines.size(); i ++)
	{
		of << veclines.at(i) << std::endl;
	}
	of.close();
}


bool CStream::RetriveFolderFiles(const wchar_t* pszFolderPath, std::vector<WIN32_FIND_DATA>& vecFileData)
{
	// append the \* for folder.
	CString strWildcard(pszFolderPath);
	if (strWildcard.Find(_T("*")) == -1)
		strWildcard += _T("\\*");

	HANDLE hFind = INVALID_HANDLE_VALUE;
	WIN32_FIND_DATA FindFileData;
	hFind = FindFirstFile(strWildcard.GetBuffer(), &FindFileData);
	if (hFind == INVALID_HANDLE_VALUE) 
	{
		_tprintf (_T("Invalid file handle. Error is %u.\n"), GetLastError());
		return false;
	} 
	else 
	{
		if (wcscmp(FindFileData.cFileName, _T(".")) != 0 && wcscmp(FindFileData.cFileName, _T("..")) != 0)	// skip . and .. files; otherwise, we'd recur infinitely!
		{
			_tprintf (TEXT("Fils name is %s.\n"), FindFileData.cFileName);
			vecFileData.push_back(FindFileData);
		}

		// List all the other files in the directory.
		while (FindNextFile(hFind, &FindFileData) != 0) 
		{
			if (wcscmp(FindFileData.cFileName, _T(".")) != 0 && wcscmp(FindFileData.cFileName, _T("..")) != 0)	// skip . and .. files; otherwise, we'd recur infinitely!
			{
				_tprintf (TEXT("Fils name is %s.\n"), FindFileData.cFileName);
				vecFileData.push_back(FindFileData);
			}
		}

		FindClose(hFind);

		DWORD dwError = GetLastError();
		if (dwError != ERROR_NO_MORE_FILES) 
		{
			_tprintf (TEXT("FindNextFile error. Error is %u.\n"), dwError);
		}
	}

	return true;
}

CString CStream::SearchFile(CString strKey, CString strFolders)
{
	std::vector<CString> vecFolders;
	if(CStream::Split(strFolders, _T(';'), vecFolders))
	{
		for (size_t i = 0; i < vecFolders.size(); i ++)
		{
			CString strFilePath = vecFolders[i];
			strFilePath += _T("\\");
			strFilePath += strKey;

			if (!_waccess(strFilePath.GetBuffer(), 0))
			{
				return strFilePath;
			}
		}
	}

	return _T("");
}
//
//bool CStream::RetriveFolderFiles(CString strFPath, std::vector<CString>& vecFileName, bool bRecursive = false, CString strPrefix/* = ""*/)
//{
//	CString strFolderPath = strFPath;
//	if (strFolderPath.Find('*') == -1)
//		strFolderPath += "\\*.*";
//	
//	CFileFind finder;
//	BOOL bWorking = finder.FindFile(strFolderPath.GetBuffer());
//	while (bWorking)
//	{
//		bWorking = finder.FindNextFile();
//
//		// skip . and .. files; otherwise, we'd recur infinitely!		
//		if (finder.IsDots()) 
//			continue;
//
//		CString strName = finder.GetFileName();
//		CString strNewName = strName;		
//		if(strPrefix != "")
//		{
//			strNewName = strPrefix + "\\" + strName;
//		}
//		
//		if (finder.IsDirectory() && bRecursive)
//		{
//			CString strNewPath = strFPath + "\\" + strName;	
//			CString strNewPrefix = strNewName;
//			RetriveFolderFiles(strNewPath, vecFileName, strNewPrefix, bRecursive);
//		}
//		else
//			vecFileName.push_back(strNewName);		
//	}
//
//	finder.Close();
//
//	return true;
//}


CString CStream::CreateGUID(bool bWithBrace /*= true*/)
{
    GUID newguid;
    ::CoCreateGuid(&newguid);

    OLECHAR olestr[MAX_GUID_LENGTH];
    StringFromGUID2(newguid, olestr, MAX_GUID_LENGTH);

	CString strRet(olestr);

	if (!bWithBrace)
	{
		strRet = strRet.Mid(0, strRet.GetLength() - 1);
		strRet = strRet.Mid(1, strRet.GetLength() - 1);
	}

    return strRet;
}

//
// return the first segment CString split by strHead and strEnd in right order
// for example:
//		Source: {#BuildPath}\data\plm.dat; DestDir: {app}\data; Flags: {#FileFlags}; Components: Core
//		segments split by "Source:" and ";" is:
//			" {#BuildPath}\data\plm.dat"
// since the last part not end with  ";", we accept the "\n" character to get the segment from strHead to CString's end
CString CStream::GetSegment(const CString& strSrc, const CString& strHead, const CString& strEnd)
{
	CString strOutSegment;

	int iHeadLen = strHead.GetLength();

	int	iHead, iEnd;
	iHead = strSrc.Find(strHead);
	iEnd  = (strEnd == "\n") ? strSrc.GetLength() : strSrc.Find(strEnd, iHead + iHeadLen);	// make sure the end characters is at back

	strOutSegment = strSrc.Mid(iHead + iHeadLen, iEnd - iHead - iHeadLen);

	return strOutSegment;
}

//
// return the last segment CString split by strHead and strEnd in reverse oder
// for example:
//		{#BuildPath}\data\plm.dat;
//		the name is "plm.dat"
//
CString CStream::ExtraNameFromPath(const CString& strPath)
{
	if (strPath.IsEmpty())
		return _T("");

	int iLastSlash = strPath.ReverseFind(_T('\\'));
	if (iLastSlash < 0)
		return _T("");	

	CString strName = strPath.Mid(iLastSlash + 1, strPath.GetLength() - iLastSlash - 1);
	strName.Trim();

	return strName;
}

//
CString CStream::ExtraDirectoryPath(const CString& strPath)
{
	if (strPath.IsEmpty())
		return _T("");

	int iLastSlash = strPath.ReverseFind(_T('\\'));
	if (iLastSlash < 0)
		return _T("");	

	CString strDirectoryPath = strPath.Mid(0, iLastSlash);
	strDirectoryPath.Trim();

	return strDirectoryPath;
}

//
// Extract the direct parent folder name
//
CString CStream::ExtraDirectParent(const CString& strPath)
{
	if (strPath.IsEmpty())
		return _T("");

	CString strDirectoryPath = CStream::ExtraDirectoryPath(strPath);

	int iLastSlash = strDirectoryPath.ReverseFind(_T('\\'));
	if (iLastSlash < 0)
		return _T("");	

	CString strParentFolder = strDirectoryPath.Mid(iLastSlash + 1, strDirectoryPath.GetLength() - iLastSlash - 1);

	return strParentFolder;
}


bool CStream::Split(CString str, char szsplit, std::vector<CString>& vecStrs)
{
	if(str.IsEmpty())
		return false;

	while(str.Find(szsplit) != -1)
	{
		int iPos = str.Find(szsplit);
		CString strSegment = str.Mid(0, iPos);
		vecStrs.push_back(strSegment);

		str = str.Mid(iPos + 1, str.GetLength() - iPos - 1);
	}

	vecStrs.push_back(str);

	return true;
}